// 版权归 瞄你个汪 所有。使用本代码应遵守相关法律法规和Apache 2.0开源许可要求。
package top.geeke.database;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyNamer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import top.geeke.config.SysUserSessionManager;
import top.geeke.toolkit.JwtUtils;
import top.geeke.entity.SysUser;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

/**
 * <p>
 * 表字段填充拦截器
 * </p>
 * @author 瞄你个汪
 * @since 2024-05-01 12:00:00
 */
@Slf4j
@Component
public class TableMetaObjectHandler implements MetaObjectHandler {
    @Autowired
    SysUserSessionManager sessionManager;

    @Override
    public void insertFill(MetaObject metaObject) {
        SysUserSessionManager.SysUserSession session = sessionManager.getUserSession();
        this.strictInsertFill(metaObject, getFieldName(SysUser::getCreateTime), LocalDateTime.class, LocalDateTime.now());

        consumerFieldNameAndMetaValue(metaObject, SysUser::getCreateByName, (fieldName, metaValue) ->
                this.strictInsertFill(metaObject, fieldName, String.class, session == null ? metaValue : session.getRealName()));

        consumerFieldNameAndMetaValue(metaObject, SysUser::getCreateById, (fieldName, metaValue) ->
                this.strictInsertFill(metaObject, fieldName, Long.class, session == null ? metaValue : session.getId()));

        consumerFieldNameAndMetaValue(metaObject, SysUser::getTenantId, (fieldName, metaValue) ->
                this.strictInsertFill(metaObject, fieldName, Long.class, session == null ? metaValue : session.getTenantId()));

        consumerFieldNameAndMetaValue(metaObject, SysUser::getOrgId, (fieldName, metaValue) ->
                this.strictInsertFill(metaObject, fieldName, Long.class, session == null ? metaValue : session.getOrgId()));
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        SysUserSessionManager.SysUserSession session = sessionManager.getUserSession();
        this.strictUpdateFill(metaObject, getFieldName(SysUser::getUpdateTime), LocalDateTime.class, LocalDateTime.now());

        consumerFieldNameAndMetaValue(metaObject, SysUser::getUpdateByName, (fieldName, metaValue) ->
                this.strictUpdateFill(metaObject, fieldName, String.class, session == null ? metaValue : session.getRealName()));

        consumerFieldNameAndMetaValue(metaObject, SysUser::getUpdateById, (fieldName, metaValue) ->
                this.strictUpdateFill(metaObject, fieldName, Long.class, session == null ? metaValue : session.getId()));
    }

    private final Map<String, String> fieldNameMap = new HashMap<>();

    /**
     * 函数式填充方法
     * @param meta 填充实体相关信息
     * @param column 字段
     * @param consumer 回调
     * @param <T> 字段类型
     */
    private <T> void consumerFieldNameAndMetaValue(MetaObject meta, SFunction<SysUser, T> column, BiConsumer<String, T> consumer) {
        String fieldName = getFieldName(column);
        consumer.accept(fieldName, meta.hasGetter(fieldName) ? (T)meta.getValue(fieldName) : null);
    }

    /**
     * 获取字段名
     * @param column 字段方法
     * @return 字段名
     * @param <T> 字段类型
     */
    private <T> String getFieldName(SFunction<SysUser, T> column) {
        String methodName = LambdaUtils.extract(column).getImplMethodName();
        if (fieldNameMap.containsKey(methodName)) return fieldNameMap.get(methodName);
        String fieldName = PropertyNamer.methodToProperty(methodName);
        fieldNameMap.put(methodName, fieldName);
        return fieldName;
    }
}
